﻿using System.Text;
using Newtonsoft.Json;
using FileImpl = System.IO.File;

namespace KinonekoSoftware.JuXiaoYouDB.Internals
{
    public static class JSON
    {
        private static readonly JsonSerializerSettings TypeHandler = new JsonSerializerSettings
        {
            TypeNameHandling = TypeNameHandling.All,
        };
        
        private static readonly JsonSerializerSettings NonTypeHandler = new JsonSerializerSettings();


        #region File

        
        
        public static T File<T>(string fileName, bool handleTypeName = true) where T : class
        {
            var setting = handleTypeName ? TypeHandler : NonTypeHandler;
            var payload = FileImpl.ReadAllText(fileName);
            return JsonConvert.DeserializeObject<T>(payload, setting);
        }
        
        public static T File<T>(byte[] buffer, bool handleTypeName = true) where T : class
        {
            var setting = handleTypeName ? TypeHandler : NonTypeHandler;
            var payload = Encoding.UTF8.GetString(buffer);
            return JsonConvert.DeserializeObject<T>(payload, setting);
        }
        
        public static T File<T>(string fileName, Func<T> factory, bool handleTypeName = true) where T : class
        {
            var setting = handleTypeName ? TypeHandler : NonTypeHandler;
            try
            {
                var payload = FileImpl.ReadAllText(fileName);
                return JsonConvert.DeserializeObject<T>(payload, setting);
            }
            catch
            {
                var instance = factory();
                var payload  = JsonConvert.SerializeObject(instance, Formatting.Indented, setting);
                FileImpl.WriteAllText(fileName, payload);
                return instance;
            }
        }
        
        
        public static async Task<T> FileAsync<T>(string fileName, bool handleTypeName = true) where T : class
        {
            var setting = handleTypeName ? TypeHandler : NonTypeHandler;
            var payload = await FileImpl.ReadAllTextAsync(fileName);
            return JsonConvert.DeserializeObject<T>(payload, setting);
        }
        
        public static async Task<T> FileAsync<T>(string fileName, Func<T> factory, bool handleTypeName = true) where T : class
        {
            var setting = handleTypeName ? TypeHandler : NonTypeHandler;
            try
            {
                var payload = await FileImpl.ReadAllTextAsync(fileName);
                return JsonConvert.DeserializeObject<T>(payload, setting);
            }
            catch
            {
                var instance = factory();
                var payload  = JsonConvert.SerializeObject(instance, Formatting.Indented, setting);
                await FileImpl.WriteAllTextAsync(fileName, payload);
                return instance;
            }
        }

        #endregion
        
        #region Document

        
        
        public static T Document<T>(string payload, bool handleTypeName = true) where T : class
        {
            var setting = handleTypeName ? TypeHandler : NonTypeHandler;
            return JsonConvert.DeserializeObject<T>(payload, setting);
        }
        
        public static T Document<T>(string payload, Func<T> factory, bool handleTypeName = true) where T : class
        {
            var setting = handleTypeName ? TypeHandler : NonTypeHandler;
            try
            {
                return JsonConvert.DeserializeObject<T>(payload, setting);
            }
            catch
            {
                return factory();
            }
        }

        #endregion

        #region Dump
        
        /// <summary>
        /// 写入
        /// </summary>
        /// <param name="instance"></param>
        /// <param name="handleTypeName"></param>
        /// <typeparam name="T"></typeparam>
        public static byte[] Dump<T>(T instance, bool handleTypeName = true) where T : class
        {
            var setting = handleTypeName ? TypeHandler : NonTypeHandler;
            var payload = JsonConvert.SerializeObject(instance, Formatting.Indented, setting);
            return Encoding.UTF8.GetBytes(payload);
        }

        /// <summary>
        /// 写入
        /// </summary>
        /// <param name="instance"></param>
        /// <param name="fileName"></param>
        /// <param name="handleTypeName"></param>
        /// <typeparam name="T"></typeparam>
        public static void Dump<T>(T instance, string fileName, bool handleTypeName = true) where T : class
        {
            var setting = handleTypeName ? TypeHandler : NonTypeHandler;
            var payload = JsonConvert.SerializeObject(instance, Formatting.Indented, setting);
            FileImpl.WriteAllText(fileName, payload);
        }
        
        /// <summary>
        /// 写入
        /// </summary>
        /// <param name="instance"></param>
        /// <param name="fileName"></param>
        /// <param name="handleTypeName"></param>
        /// <typeparam name="T"></typeparam>
        public static async Task DumpAsync<T>(T instance, string fileName, bool handleTypeName = true) where T : class
        {
            var setting = handleTypeName ? TypeHandler : NonTypeHandler;
            var payload = JsonConvert.SerializeObject(instance, Formatting.Indented, setting);
            await FileImpl.WriteAllTextAsync(fileName, payload);
        }
        #endregion
    }
}